<?php

namespace app\common\model\banxi\core;

use app\common\enums\AccountTypeEnum;
use app\common\enums\ClassHourBusinessTypeEnum;
use app\common\enums\ClassHourStatusEnum;
use app\common\enums\ClassHourTypeEnum;
use app\common\enums\core\PayTypeEnum;
use app\common\enums\core\RechargeTypeEnum;
use app\common\model\banxi\organization\Organization;
use app\common\model\banxi\student\Student;
use app\common\model\common\BaseModel;
use app\common\service\core\CoreAccountClassHourService;
use app\common\service\SnowflakeService;
use ba\Exception;
use think\db\exception\PDOException;
use think\exception\ValidateException;
use think\facade\Cache;
use think\model\concern\SoftDelete;

/**
 * 账户课时表
 */
class CoreClassHourDetail extends BaseModel
{
    use SoftDelete;

    protected $name = 'banxi_core_class_hour_detail';

    protected $autoWriteTimestamp = true;

    protected $deleteTime = 'del';

    protected $defaultSoftDelete = 0;

    protected $append = [
        'classHourTypeCn',
        'payerAccountTypeCn',
        'receiverAccountTypeCn',
        'rechargeTypeCn',
        'businessTypeCn',
        'payTypeCn',
        'statusCn'
    ];

    protected $type = [
        'id' => 'string',
        'del' => 'string',
        'payerStudentId' => 'string',
        'receiverStudentId' => 'string',
        'isLinePay' => 'boolean',
        'createTime' => 'timestamp:Y-m-d H:i:s',
        'updateTime' => 'timestamp:Y-m-d H:i:s',
    ];

    //-----------------------------------------------------------------------------------
    //｜                                   获取器                                       ｜
    //-----------------------------------------------------------------------------------

    public function getClassHourTypeCnAttr($value, $data)
    {
        $value = $value ?: ($data['classHourType'] ?? '');
        return (new ClassHourTypeEnum())->getDescription($value) ?? '';
    }

    public function getPayerAccountTypeCnAttr($value, $data)
    {
        $value = $value ?: ($data['payerAccountType'] ?? '');
        return (new AccountTypeEnum())->getDescription($value) ?? '';
    }

    public function getReceiverAccountTypeCnAttr($value, $data)
    {
        $value = $value ?: ($data['receiverAccountType'] ?? '');
        return (new AccountTypeEnum())->getDescription($value) ?? '';
    }

    public function getBusinessTypeCnAttr($value, $data)
    {
        $value = $value ?: ($data['businessType'] ?? '');
        return (new ClassHourBusinessTypeEnum())->getDescription($value) ?? '';
    }

    public function getStatusCnAttr($value, $data)
    {
        $value = $value ?: ($data['status'] ?? '');
        return (new ClassHourStatusEnum())->getDescription($value) ?? '';
    }

    public function getPayTypeCnAttr($value, $data)
    {
        $value = $value ?: ($data['payType'] ?? '');
        return (new PayTypeEnum())->getDescription($value) ?? '';
    }

    public function getRechargeTypeCnAttr($value, $data)
    {
        $value = $value ?: ($data['rechargeType'] ?? '');
        return (new RechargeTypeEnum())->getDescription($value) ?? '';
    }

    //-----------------------------------------------------------------------------------
    //｜                                   处理方法                                       ｜
    //-----------------------------------------------------------------------------------


    public function wrapperAdminDBList($data)
    {
        $studentIds = [];
        $organizationIds = [];
        foreach ($data as $item) {
            if (!empty($item['payerStudentId'])) {
                $studentIds[] = $item['payerStudentId'];
            }
            if (!empty($item['receiverStudentId'])) {
                $studentIds[] = $item['receiverStudentId'];
            }
            if (!empty($item['payerOrganizationId'])) {
                $organizationIds[] = $item['payerOrganizationId'];
            }
            if (!empty($item['receiverOrganizationId'])) {
                $organizationIds[] = $item['receiverOrganizationId'];
            }
        }
        $studentList = [];
        if (!empty($studentIds)) {
            $studentList = Student::whereIn('id', $studentIds)->select();
        }
        $organizationList = [];
        if (!empty($organizationIds)) {
            $organizationList = Organization::whereIn('id', $organizationIds)->select();
        }
        foreach ($data as &$datum) {
            $datum = $this->wrapperAdmin($organizationList, $studentList, $datum);
        }
        unset($datum);
        return $data;

    }

    public function wrapperAdminDB($data)
    {
        $studentIds = [];
        $organizationIds = [];
        if ($data['payerStudentId']) {
            $studentIds[] = $data['payerStudentId'];
        }
        if ($data['receiverStudentId']) {
            $studentIds[] = $data['receiverStudentId'];
        }
        if ($data['payerOrganizationId']) {
            $organizationIds[] = $data['payerOrganizationId'];
        }
        if ($data['receiverOrganizationId']) {
            $organizationIds[] = $data['receiverOrganizationId'];
        }
        $studentList = [];
        if (!empty($studentIds)) {
            $studentList = Student::whereIn('id', $studentIds)->select();
        }
        $organizationList = [];
        if (!empty($organizationIds)) {
            $organizationList = Organization::whereIn('id', $organizationIds)->select();
        }
        return $this->wrapperAdmin($organizationList, $studentList, $data);

    }

    private function wrapperAdmin($organizationList, $studentList, $item)
    {

        $payerAccountType = $item['payerAccountType'];
        $receiverAccountType = $item['receiverAccountType'];
        switch ($payerAccountType) {
            case 1:
                $item['payerAccountName'] = "【总平台】";
                break;
            case 2:
                $payerOrganization = null;
                foreach ($organizationList as $organization) {
                    if ($organization['id'] === $item['payerOrganizationId']) {
                        $payerOrganization = $organization;
                        break;
                    }
                }
                $item['payerAccountName'] = '【机构】' . ($payerOrganization ? $payerOrganization['name'] : "已删除");
                break;
            case 3:
                $payerStudent = null;
                foreach ($studentList as $student) {
                    if ($student['id'] === $item['payerStudentId']) {
                        $payerStudent = $student;
                        break;
                    }
                }
                $item['payerAccountName'] = '【学员】' . ($payerStudent ? $payerStudent['name'] : "已删除");
                break;

        }
        switch ($receiverAccountType) {
            case 1:
                $item['receiverAccountName'] = "【总平台】";
                break;
            case 2:
                $receiverOrganization = null;
                foreach ($organizationList as $organization) {
                    if ($organization['id'] === $item['receiverOrganizationId']) {
                        $receiverOrganization = $organization;
                        break;
                    }
                }
                $item['receiverAccountName'] = '【机构】' . ($receiverOrganization ? $receiverOrganization['name'] : "已删除");
                break;
            case 3:
                $payerStudent = null;
                foreach ($studentList as $student) {
                    if ($student['id'] === $item['receiverStudentId']) {
                        $payerStudent = $student;
                        break;
                    }
                }
                $item['receiverAccountName'] = '【学员】' . ($payerStudent ? $payerStudent['name'] : "已删除");
                break;
        }

        return $item;
    }

    public function updateAccountChange(array $updateChange, array $consumer)
    {
        $detailId = $updateChange['id'] ?? 0;
        if (!$detailId) {
            $snowflakeService = new SnowflakeService(1, 1);
            $detailId = $snowflakeService->nextId();
            $updateChange['id'] = $detailId;
        }
        $classHourNum = $updateChange['classHourNum'];
        if ($classHourNum <= 0) {
            throw new ValidateException('课时操作不能小于0');
        }
        $classHourDetail = $updateChange;
        if (!isset($classHourDetail['rechargeType'])) {
            $arr = [
                ClassHourBusinessTypeEnum::E1,
                ClassHourBusinessTypeEnum::E2,
                ClassHourBusinessTypeEnum::E7,
                ClassHourBusinessTypeEnum::E8,
                ClassHourBusinessTypeEnum::E9,
                ClassHourBusinessTypeEnum::E10,
            ];
            if (in_array($classHourDetail['businessType'], $arr)) {
                $classHourDetail['rechargeType'] = RechargeTypeEnum::E1;
            } else {
                $classHourDetail['rechargeType'] = RechargeTypeEnum::E2;
            }
        }
        $payerAccountType = $updateChange['payerAccountType'];
        $receiverAccountType = $updateChange['receiverAccountType'];
        $payerLockKey = null;
        $receiverLockKey = null;
        $AccountTypeEnum = new AccountTypeEnum();
        $payerAccountTypeName = $AccountTypeEnum->getDescription($payerAccountType);
        switch ($payerAccountType) {
            case AccountTypeEnum::ORGAN:
                $payerLockKey = "CoreClassHourDetailLock:.{$payerAccountTypeName}-{$updateChange['payerAccountId']}";
                $classHourDetail['payerOrganizationId'] = $classHourDetail['payerAccountId'];
                if (empty($classHourDetail['payerRealOrganizationId'])) {
                    $classHourDetail['payerRealOrganizationId'] = $classHourDetail['payerAccountId'];
                }
                break;
            case AccountTypeEnum::STUDENT:
                $payerLockKey = "CoreClassHourDetailLock:.{$payerAccountTypeName}-{$updateChange['payerAccountId']}";
                $classHourDetail['payerStudentId'] = $classHourDetail['payerAccountId'];
                break;
        }
        $receiverAccountTypeName = $AccountTypeEnum->getDescription($receiverAccountType);
        switch ($receiverAccountType) {
            case AccountTypeEnum::ORGAN:
                $receiverLockKey = "CoreClassHourDetailLock:.{$receiverAccountTypeName}-{$updateChange['receiverAccountId']}";
                $classHourDetail['receiverOrganizationId'] = $classHourDetail['receiverAccountId'];
                break;
            case AccountTypeEnum::STUDENT:
                $receiverLockKey = "CoreClassHourDetailLock:.{$receiverAccountTypeName}-{$updateChange['receiverAccountId']}";
                $classHourDetail['receiverStudentId'] = $classHourDetail['receiverAccountId'];
                break;
        }
        if ($consumer) {
            $classHourDetail = array_merge($classHourDetail, $consumer);
        }
        $payerLock = null;
        $receiverLock = null;
        try {
            if ($payerLockKey) {
                $payerLock = Cache::set($payerLockKey, 1, 30);
            }
            if ($receiverLockKey) {
                $receiverLock = Cache::set($receiverLockKey, 1, 30);
            }
            if ($payerLockKey && !$payerLock) {
                throw new ValidateException('账户操作繁忙，请稍后重试');
            }
            if ($receiverLockKey && !$receiverLock) {
                throw new ValidateException('账户操作繁忙，请稍后重试');
            }
            $this->save($classHourDetail);
            $this->updateOutAccount($classHourDetail);
            $status = $classHourDetail['status'];
            if ($status == ClassHourStatusEnum::SUCCESS) {
                $this->updateInAccount($classHourDetail);
            }
        } catch (Exception|PDOException|ValidateException $e) {
            throw new ValidateException($e->getMessage());
        } finally {
            if ($payerLockKey) {
                Cache::delete($payerLockKey);
            }
            if ($receiverLockKey) {
                Cache::delete($receiverLockKey);
            }
        }
        return $this->getData();
    }

    public function updateOutAccount($classHourDetail)
    {
        $accountId = $classHourDetail['payerAccountId'];
        $accountType = $classHourDetail['payerAccountType'];
        if ($accountType == AccountTypeEnum::PLATFORM) {
            return true;
        }
        $accountClassHourService = new CoreAccountClassHourService();
        $accountClassHour = $accountClassHourService->getByAccountIdAndType($accountId, $accountType);
        $detailId = $classHourDetail['id'];
        $classHourType = $classHourDetail['classHourType'];
        $classHourNum = $classHourDetail['classHourNum'];
        $coreAccountClassHour = new CoreAccountClassHour();
        $beforeClassHourNum = $coreAccountClassHour->classMinutes($classHourType, $accountClassHour);
        $afterClassHourNum = bcsub($beforeClassHourNum, $classHourNum, 0);
        if ($afterClassHourNum < 0) {
            throw new ValidateException("课时不足【{$classHourDetail['describe']}】");
        }
        $classMinutesFreeze = $coreAccountClassHour->classMinutesFreeze($classHourType, $accountClassHour);
        if (bcsub($afterClassHourNum, $classMinutesFreeze, 0) < 0) {
            throw new ValidateException('可用课时不足');
        }
        $cnt = $accountClassHourService->updateClassHour($accountId, $accountType, $classHourType, $beforeClassHourNum, $afterClassHourNum, null, null);
        if (!$cnt) {
            throw new ValidateException('更新账户课时失败');
        }
        $snowflakeService = new SnowflakeService(1, 1);
        $coreClassHourRw = new CoreClassHourRw();
        $classHourRw = [
            'id' => $snowflakeService->nextId(),
            'detailId' => $detailId,
            'classHourNum' => $classHourNum,
            'beforeClassHourNum' => $beforeClassHourNum,
            'afterClassHourNum' => $afterClassHourNum,
            'tradeType' => 0
        ];
        $AccountOwnedDate = $coreClassHourRw->setAccountOwnedId($accountId, $accountType);
        $classHourRw = array_merge($classHourRw, $AccountOwnedDate);
        return $coreClassHourRw->save($classHourRw);
    }

    public function updateInAccount($classHourDetail)
    {
        $accountId = $classHourDetail['receiverAccountId'];
        $accountType = $classHourDetail['receiverAccountType'];
        $detailId = $classHourDetail['id'];
        if ($accountType == AccountTypeEnum::PLATFORM) {
            return true;
        }
        $accountClassHourService = new CoreAccountClassHourService();
        $accountClassHour = $accountClassHourService->getByAccountIdAndType($accountId, $accountType);
        $classHourType = $classHourDetail['classHourType'];
        $businessType = $classHourDetail['businessType'];
        $classHourNum = $classHourDetail['classHourNum'];
        $coreAccountClassHour = new CoreAccountClassHour();
        $beforeClassHourNum = $coreAccountClassHour->classMinutes($classHourType, $accountClassHour);
        $afterClassHourNum = bcadd($beforeClassHourNum, $classHourNum, 0);
        //累计课时允许类型
        $totalClassHour = null;
        $businessTypes = [
            ClassHourBusinessTypeEnum::E1, ClassHourBusinessTypeEnum::E2, ClassHourBusinessTypeEnum::E7,
            ClassHourBusinessTypeEnum::E8, ClassHourBusinessTypeEnum::E9, ClassHourBusinessTypeEnum::E10
        ];
        if (in_array($businessType, $businessTypes)) {
            $classMinutesTotal = $coreAccountClassHour->classMinutesTotal($classHourType, $accountClassHour);
            $totalClassHour = bcadd($classMinutesTotal, $classHourNum, 0);
        }
        $buyTotalClassHour = null;
        //购买累计课时允许类型
        $payBusinessTypes = [
            ClassHourBusinessTypeEnum::E1, ClassHourBusinessTypeEnum::E2, ClassHourBusinessTypeEnum::E7
        ];
        if (in_array($businessType, $payBusinessTypes) && $classHourDetail['rechargeType'] == RechargeTypeEnum::E1) {
            $buyClassMinuteTotal = $coreAccountClassHour->buyClassMinuteTotal($classHourType, $accountClassHour);
            $buyTotalClassHour = bcadd($buyClassMinuteTotal, $classHourNum, 0);
        }
        $cnt = $accountClassHourService->updateClassHour($accountId, $accountType, $classHourType, $beforeClassHourNum, $afterClassHourNum, $totalClassHour, $buyTotalClassHour);
        if (!$cnt) {
            throw new ValidateException('操作繁忙，请稍后重试');
        }
        $snowflakeService = new SnowflakeService(1, 1);
        $coreClassHourRw = new CoreClassHourRw();
        $classHourRw = [
            'id' => $snowflakeService->nextId(),
            'detailId' => $detailId,
            'classHourNum' => $classHourNum,
            'beforeClassHourNum' => $beforeClassHourNum,
            'afterClassHourNum' => $afterClassHourNum,
            'tradeType' => 1
        ];
        $AccountOwnedDate = $coreClassHourRw->setAccountOwnedId($accountId, $accountType);
        $classHourRw = array_merge($classHourRw, $AccountOwnedDate);
        return $coreClassHourRw->save($classHourRw);
    }

    //-----------------------------------------------------------------------------------
    //｜                                   模型关联                                       ｜
    //-----------------------------------------------------------------------------------


}